//
//  ARRequest.swift
//  AquaRaft
//
//  Created by 何启亮 on 2024/3/28.
//

import Foundation
import Alamofire

struct ArrayEncoding: ParameterEncoding {
    
    private let array: [Any]

    init(array: [Any]) {
        self.array = array
    }

    func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
        var urlRequest = try urlRequest.asURLRequest()

        let data = try JSONSerialization.data(withJSONObject: array, options: [])

        if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
            urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
        }

        urlRequest.httpBody = data

        return urlRequest
    }
}

struct DataEncoding: ParameterEncoding {
    
    private let data: Data

    init(data: Data) {
        self.data = data
    }

    func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
        var urlRequest = try urlRequest.asURLRequest()

        if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
            urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
        }

        urlRequest.httpBody = data

        return urlRequest
    }
}

/// 请求的基类
class ARRequest {
    
    // MARK: - Subclass override
    
    /// 请求方法
    var httpMethod: HTTPMethod {
        get {
            return .get
        }
    }
    
    /// 请求参数
    var parameters: Parameters? = nil
    
    /// 请求头
    var headers: [String: String]? = nil
    
    /// 编码 - 默认json
    var encoder: ParameterEncoding {
        get {
            if case .post = httpMethod {
                return JSONEncoding.default
            }
            return URLEncoding.default
        }
    }
    
    /// api
    var api: String {
        get {
            fatalError("Must override by subclass")
        }
    }
    
    /// host
    var host: String {
        get {
            return "http://test-app.cosmofusionly.xyz"
//            #if DEBUG
//            return "http://test-app.cosmofusionly.xyz"
//            #else
//            return "https://test-app.cosmofusionly.xyz"
//            #endif
        }
    }
    
    // MARK: - Private property
    
    /// 当前的请求
    private var currentRequest: DataRequest?
    
    // MARK: - Action
    
    /// 可以传入一个遵循Decodable的模型，自动decode
    /// 如果传入了 Model，然后解析失败，会返回错误
    final func request<Model: Decodable>(of type: Model.Type = AnyDecodable.self, completion: @escaping (_ response: AFDataResponse<ARResponseModel>, _ result: ARRequestResult<Model>) -> Void) {
        
        let url = host + api
        // 设置请求头
        let commonHeaders = generateHeader()
        
        // 参数
        let commonParams = generateParams()
        
        if let currentRequest = currentRequest, currentRequest.isCancelled == false {
            currentRequest.cancel()
            self.currentRequest = nil
        }
        currentRequest = AF.request(url, method: httpMethod, parameters: commonParams, encoding: encoder, headers: HTTPHeaders(commonHeaders))
        currentRequest?.responseDecodable(of: ARResponseModel.self, queue: DispatchQueue.main) { [weak self] response in
            
            self?.currentRequest = nil
            switch response.result {
            // 失败
            case .failure(let error):
                completion(response, .faild(err: .serviceError(error: error)))
                return
                // 成功
            case .success(let responseModel):
                // 判断接口是否成功
                if responseModel.code != 0 {
                    completion(response, .faild(err: .apiError(code: responseModel.code, msg: responseModel.msg ?? "Api error")))
                    return
                }
                
                // 如果为默认，则不用去解码
                if type == AnyDecodable.self {
                    // 不需要解析
                    if let data = responseModel.data {
                        completion(response, .success(model: data as! Model))
                    } else {
                        // data为空
                        completion(response, .successWithoutResponse)
                    }
                    
                    return
                }
                
                // 判断类型 - 只能转码Array和Dictionary
                guard let data = responseModel.data else {
                    completion(response, .faild(err: .modelConvertError(error: nil)))
                    return
                }
                
                do {
                    let encoder = JSONEncoder()
                    let jsonData: Data
                    switch data {
                    case .array(let jsonArray):
                        jsonData = try encoder.encode(jsonArray)
                        break
                    case .dictionary(let json):
                        jsonData = try encoder.encode(json)
                        break
                    default:
                        // 转换失败
                        completion(response, .faild(err: .modelConvertError(error: nil)))
                        return
                    }
                    
                    // 转码
                    let decoder = JSONDecoder()
                    let model = try decoder.decode(type, from: jsonData)
                    completion(response, .success(model: model))
                } catch {
                    // 转换失败
                    completion(response, .faild(err: .modelConvertError(error: error)))
                }
                return
            }
        }
    }
    
    /// 取消
    final func cancel() {
        // 取消 
        if let currentRequest = currentRequest, currentRequest.isCancelled == false {
            currentRequest.cancel()
            self.currentRequest = nil
        }
    }
    
    // MARK: Helper
    
    func generateHeader() -> [String: String] {
        var commonHeaders = ARRequestHelper.commonHeaders()
        if let headers = headers {
            commonHeaders.merge(headers) { (current, _) in current}
        }
        return commonHeaders
    }
    
    func generateParams() -> Parameters {
        var commonParams: [String: Any] = [:]
        if let parameters = parameters {
            commonParams.merge(parameters) { (current, _) in current}
        }
        return commonParams
    }
    
}
